﻿/***************************************************************
 * Class Name : Goal
 * Function   : A base class for all Goals in GOAP system
 *				
 * Created by : Marek Rabas
 **************************************************************/



using System;
using System.Collections.Generic;
using UnityEngine;


public abstract class GOAPGoal : System.Object
{
    public Agent Owner;// { get { return Ai; } private set { Ai = value; } }

    /// <summary>
    /// goal行为目标的优先级
    /// </summary>
    public float GoalRelevancy;//{ get { return GoalRelevancy; } protected set { GoalRelevancy = value; } }

    public E_GOAPGoals GoalType;// { get { return GoalType; } private set { GoalType = value; } }

    public bool Active = false;// { get { return Active; } private set { Active = value; } }
    public bool Critical = false; // Its top most goal, if it set to higher value it could terminate other goal !!!

    private GOAPPlan Plan;
    protected float NextEvaluationTime;// { get { return NextEvaluationTime; } protected set { NextEvaluationTime = value; } }

    static int id;
    public int UID;

    /// <summary>
    /// 为规划设置世界状态满足条件
    /// 设置一个目标（Goal）在“行为规划”阶段所期望达到的世界状态条件（即：达成目标所需满足的状态）
    /// </summary>
    /// <param name="worldState"></param>
    public abstract void SetWSSatisfactionForPlanning(WorldState worldState);

    /// <summary>
    /// 判断当前世界状态是否已经满足了该目标在“规划阶段”所定义的满足条件。
    /// 这是 GOAP 在执行行为规划（Plan）时，用来检查目标是否“已经达成”的逻辑判断方法。
    /// 备注：该方法与IsSatisfied类似，不过执行时机不一样
    /// IsWSSatisfiedForPlanning：计划生成阶段
    /// IsSatisfied：实际执行阶段
    /// 简单说：IsWSSatisfiedForPlanning 是**“理论上达成目标了吗？”**
    /// 而 IsSatisfied 是**“现在真的完成目标了吗？”**
    /// </summary>
    /// <param name="worldState"></param>
    /// <returns></returns>
    public abstract bool IsWSSatisfiedForPlanning(WorldState worldState);


    //relevancy:关联
    public abstract float GetMaxRelevancy();

    /// <summary>
    /// 计算目标优先级
    /// 根据当前世界状态，计算一个目标（Goal）的重要程度
    /// 然后由系统选出“最相关”或“最紧急”的目标去执行
    /// </summary>
    public abstract void CalculateGoalRelevancy(); // how important is this goal !!!
    public void ClearGoalRelevancy() { GoalRelevancy = 0; }

    public virtual void SetDisableTime() { NextEvaluationTime = Time.timeSinceLevelLoad + UnityEngine.Random.Range(0.1f, 0.2f); }

    public virtual bool ReplanRequired() { return false; }// if goal need to be replanned !!!!

    /// <summary>
    /// 在运行时判断目标是否完成
    /// 备注：该方法与IsWSSatisfiedForPlanning类似，不过执行时机不一样
    /// IsWSSatisfiedForPlanning：计划生成阶段
    /// IsSatisfied：实际执行阶段
    /// 简单说：IsWSSatisfiedForPlanning 是**“理论上达成目标了吗？”**
    /// 而 IsSatisfied 是**“现在真的完成目标了吗？”**
    /// </summary>
    /// <returns></returns>
    public abstract bool IsSatisfied();

    public virtual bool IsDisabled() { return NextEvaluationTime > Time.timeSinceLevelLoad; }

    protected GOAPGoal(E_GOAPGoals type, Agent ai)
    {
        GoalType = type;
        Owner = ai;
    }

    public abstract void InitGoal();

    /**
    * Updates the goal. This involves getting the plan, checking if the current step(i.e. action is complete), if so advance the plan
    */
    public bool UpdateGoal()
    {
        //Check if plan exists, if not quit
        if (Plan == null)
            return false;

        Plan.Update();

        //Check if the plan step is complete, if so advance if not do nothing :)
        if (Plan.IsPlanStepComplete())
            return Plan.AdvancePlan();

        return true;
    }

    public virtual bool Activate(GOAPPlan plan)
    {
        UID = ++id;

        Active = true;
        Plan = plan;
        
        return Plan.Activate(Owner, this);
    }

    public virtual void ReplanReset()
    {
        Active = false;
        if (Plan != null)
            Plan.Deactivate();

        Plan = null;

        //if (Owner.debugGOAP) Debug.Log(Time.timeSinceLevelLoad + " " + this.ToString() + " - replan Reset");
    }

    public virtual void Reset()
    {
        Active = false;
        if (Plan != null)
            Plan.Deactivate();

        Plan = null;
        ClearGoalRelevancy();

        //if (Owner.debugGOAP) Debug.Log(Time.timeSinceLevelLoad + " " + this.ToString() + " - Reset");
    }
    /* 
     * do some cleaning shit here
     */
    public virtual void Deactivate()
    {
        Active = false;
        if (Plan != null)
            Plan.Deactivate();

        Plan = null;
        ClearGoalRelevancy();
        SetDisableTime();

        //if (Owner.debugGOAP) Debug.Log(Time.timeSinceLevelLoad + " " + this.ToString() + " - Deactivated");
    }

    /**
    * Checks whether the plan is interruptible or not
    * @return true if the plan is interruptible, false otherwise
    */

    public bool IsPlanInterruptible()
    {
        return Plan == null ? true : Plan.IsPlanStepInterruptible();
    }

    /**
    * Checks whether the plan is valid
    * @return true if the plan is valid, false otherwise
    */
    public virtual bool IsPlanValid()
    {
        return Plan == null ? false : Plan.IsPlanValid();
    }


    public bool IsPlanFinished()
    {
        return Plan == null ? true : Plan.IsDone();
    }



    //If a plan fails to be built, clear the relevancy and try again
    public virtual void HandlePlanBuildFailure()
    {
        ClearGoalRelevancy();
    }

    protected bool isGroundThere(Vector3 pos)
    {
        return Physics.Raycast(pos + Vector3.up, -Vector3.up, 5, 1 << 10);
    }

    public override string ToString()
    {
        return base.ToString() + " Releavancy: " + GoalRelevancy + (Active ?  "Active " : " Deactive ") + (IsDisabled() ? " Disabled " : " Enabled ");
    }

}

